import redis
from rest_framework.views import APIView
from rest_framework.response import Response
import datetime
import random
from django.db import transaction
# Create your views here.
from orders.models import *
from users.models import Users, Addr
from goods.models import Goods
from alipay import AliPay

import os
from django.conf import settings

# 支付宝的公钥
PUBLIC_URL = open(os.path.join(settings.BASE_DIR, "utils/alipay/alipay_public_key.pem")).read()
# 自己的私钥
PRIVATE_URL = open(os.path.join(settings.BASE_DIR, "utils/alipay/app_private_key.pem")).read()


# 在订单orders应用中的views.py模块，定义如下类
class MyAliPay(APIView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 初始化alipay对象
        self.alipay = AliPay(
            appid='2021000119665006',  # 你的支付宝沙箱应用的id
            app_private_key_string=PRIVATE_URL,  # 自己的私钥
            alipay_public_key_string=PUBLIC_URL,  # 支付宝的公钥
            app_notify_url=None,  # 回调地址
            sign_type='RSA2',  # 签名算法
            debug=True,  # 请求来到支付宝沙箱
        )

    # 定义生成支付地址的方法
    def get_trade_url(self, order_id, total_price):
        order_string = self.alipay.api_alipay_trade_page_pay(
            subject='商家收款',
            out_trade_no=order_id,
            total_amount=total_price,
            return_url='http://127.0.0.1:8000/orders/pay/result/',
            notify_url='http://127.0.0.1:8000/orders/pay/result/'  # 异步通知地址
        )
        return 'https://openapi.alipaydev.com/gateway.do?' + order_string


# 创建订单
class CreateOrder(MyAliPay):
    def post(self, request):

        # 1.获取前端传来的数据
        global order
        name = request.data.get('user').get('userName')
        products = request.data.get('products')  # [{"good_id":1,},{"good_id":2}]
        add = request.data.get('addr')  # 获取的是地址的id
        payMethod = request.data.get('payMethod')

        # 2. 校验  用户、用户地址
        try:
            user = Users.objects.get(username=name)
        except Exception as e:
            print(e)
            return Response({'msg': '没有此用户', 'code': 400})
        try:
            address = Addr.objects.get(id=add)
        except Exception as e:
            print(e)
            return Response({'msg': '请确认地址', 'code': 400})

        # 3. 创建订单id ：order_id 使用时间戳         年月日时分秒           +            八位数的随机字符串    +    用户的id
        order_id = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + str(random.randint(00000000, 99999999)) + str(
            user.id)

        # 总数量和总价格
        total_amount = 0  # 总价格
        total_count = 0  # 总数量
        # 开启事务
        with transaction.atomic():
            # 设置回滚点
            point = transaction.savepoint()
            try:
                # 4. 创建订单
                order = Order.objects.create(
                    order_id=order_id,  # 订单号
                    user_id=user.id,  # 用户id
                    address=address,  # 收货地址
                    freight=10,  # 运费
                    pay_method=payMethod,  # 支付方式
                    total_amount=total_amount,  # 总价
                    total_count=total_count,  # 商品总数
                )

                # 5. 创建订单商品
                for product in products:  # product 是一个商品对象
                    print('商品>>>', product)

                    # 判断库存和购买的商品数量
                    try:
                        good = Goods.objects.get(id=product.get('productID'))  # 根据商品id获取商品
                    except Exception as e:
                        print(e)
                        return Response({'msg': '该商品已经下架', "code": 400})

                    # 获取商品存库和销量
                    origin_stock = good.stock  # 存库
                    origin_count = good.count  # 销量

                    # 若库存不足,应该回滚,订单创建失败, 商品订单也创建失败
                    if product.get('num') > origin_stock:
                        # 商品存在,商品的库存 < 购买的数量, 不能下单
                        transaction.savepoint_rollback(point)  # 回滚到订单创建之前
                        return Response({'msg': "该商品库存不足", "code": 400})

                    # 判断商品的数量 销量 库存是否一样,不一样,不能创建订单及订单商品
                    result = Goods.objects.filter(
                        id=product.get('productID'),  # 商品id
                        stock=origin_stock,  # 销量
                        count=origin_count,  # 数量
                    )
                    # 进行判断不一样就回滚
                    if not result:
                        transaction.savepoint_rollback(point)  # 回滚到订单创建之前
                        return Response({'msg': '前后数据不一致', 'code': 400})

                    # 创建订单商品成功
                    OrderGoods.objects.create(
                        good_id=product.get('productID'),  # 商品id
                        count=product.get('num'),  # 商品数量
                        price=product.get('price'),  # 商品价格
                        order_id=order_id,  # 订单id
                    )

                    # 商品的存库-购买的商品数量
                    new_stock = origin_stock - product.get('num')
                    # 商品的销量+购买的商品数量
                    new_count = origin_count + product.get('num')
                    good.count = new_count
                    good.stock = new_stock
                    good.save()  # 保存更新后的存库和销量

                    # 商品的总价格和总数量
                    total_count += product.get('num')  # 总数量
                    total_amount += product.get('price') * product.get('num')  # 总价格

                # 更新订单表的总数量和总价格
                freight = 10  # 运费
                order.total_amount = total_amount + freight  # 总价格
                order.total_count = total_count  # 总数量
                order.save()  # 保存更新后的数据
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(point)  # 回滚到订单创建之前

        # 6. 把redis中的支付过的商品从redis中删除
        rdb = redis.Redis()  # 连接redis
        cart_key = "cart_%s" % user.id  # hash中的key
        cart_selected = "cart_selected_%s" % user.id  # 集合中的key
        for i in products:
            # 删除已支付的商品
            rdb.hdel(cart_key, i.get('productID'))  # 删除hash中的商品
            rdb.srem(cart_selected, i.get('productID'))  # 删除集合中的商品
        rdb.close()  # 关闭
        # 调用生成的支付地址             订单id        总价格
        trade_url = self.get_trade_url(order_id, order.total_amount)
        return Response({'msg': "下单成功", "code": 200, "url": trade_url})


# 支付成功回调
class CheckPayResult(MyAliPay):
    """告知买家支付成功"""

    def get(self, request):
        # 获取支付结果的参数
        # 字符串用query_params 获取支付结果
        # 获取订单流水号
        order_id = request.query_params.get('out_trade_no')
        # 根据订单号查询订单的支付结果
        result = self.alipay.api_alipay_trade_query(order_id)
        # 判断是否支付成功
        if result.get('trade_status') == 'TRADE_SUCCESS':
            # 此时说明支付成功

            # 修改订单状态
            order = Order.objects.get(order_id=order_id)
            order.pay_status = '1'
            order.save()
            return Response({'msg': '支付成功', 'code': 200})
        else:
            return Response({'msg': '支付失败，请重新支付!'})

        # 处理支付宝的异步通知 post notify_url
        # 需项目部署到公网

    """
    告知卖家支付的结果
    支付宝沙箱没有这功能,只能等项目上线后才能使用,这里仅做说明
    """

    def post(self, request):
        # 解析数据
        # 把返回的参数形成字典
        data_dict = {k: v for k, v in request.POST.items()}
        print("支付宝post请求：", data_dict)

        # 此时由于项目未上线, 订单的状态修改无效果
        order_id = data_dict.get('out_trade_no')

        # 验证是否支付宝发送过来的请求
        # 获取签名信息
        sign = data_dict.pop("sign")
        print("签名信息：", sign)
        # 对sign进行校验,防止伪造
        validate_result = self.alipay.verify(data_dict, sign)
        if validate_result:
            # 是支付宝发送过来的post请求
            # 是否支付成功
            if data_dict.get("trade_status") == "TRADE_SUCCESS":
                # 支付成功
                # 给支付宝的响应

                # 修改订单状态
                order = Order.objects.get(order_id=order_id)
                order.pay_status = '1'
                order.save()
                return Response({"msg": '支付成功', "code": 200})
            else:
                return Response({"msg": '支付失败', "code": 400})
        else:
            return Response({"code": 204, "msg": "非法请求！"})


# 展示订单信息
class OrderInfo(APIView):
    def post(self, request):
        # 获取前端传来的参数
        name = request.data.get('user').get("userName")
        # 判断用户是否存在
        try:
            user = Users.objects.get(username=name)
        except Exception as e:
            print(e)
            return Response({'msg': '用户不存在', 'code': 400})
        # 获取所有的订单
        orders = user.order.all()
        # 根据订单获取商品
        order_list = []
        for order in orders:
            # 根据订单获取订单shangp
            goods = order.orderGood.all()
            temp = []
            # 把每个订单的商品存放在dict中
            for good in goods:
                temp.append({
                    "productID": good.good.id,
                    "productName": good.good.sku_name,
                    "productImg": good.good.img,
                    "productPrice": good.good.price,
                    "productNum": good.good.count,
                    "orderID": order.order_id,
                    "createdTime": order.created_time,
                    # "payStatus":'待收货',
                    "payStatus": order.get_pay_status_display()
                })
            order_list.append(temp)
        return Response({'msg': '获取订单数据成功', 'code': 200, 'orders': order_list})


# 去支付
class PayOrder(MyAliPay):
    def post(self, request):
        # 获取前端传来的参数
        order_id = request.data.get('orderID')
        total_price = request.data.get('totalPrice')
        # 支付
        url = self.get_trade_url(order_id, total_price)
        return Response({'msg': '去支付', "code": 302, 'pay_url': url})


# 修改订单状态
class ConfirmReceive(APIView):
    def post(self, request):
        # 接受前端传来的订单id
        order_id = request.data.get('orderID')
        # 根据订单id  查询订单  然后修改订单状态
        try:
            order = Order.objects.get(order_id=order_id)
            # 修改状态
            order.pay_status = int(order.pay_status) + 1
            # 保存
            order.save()
            return Response({'msg': "修改状态成功", "code": 200})
        except Exception as e:
            print(e)
            return Response({'msg': "订单不存在", "code": 400})


# 删除订单中的商品
class DeleteProduct(APIView):
    def post(self, request):
        # 获取前端传来的参数
        # 订单id
        order_id = request.data.get('orderID')
        # 订单中商品id
        pid = request.data.get('productID')
        # 判断订单
        try:
            order = Order.objects.get(order_id=order_id)
        except Exception as e:
            print(e)
            return Response({'msg': '订单不存在', 'code': 400})
        # 订单存在  判断订单中的商品数量
        goods = order.orderGood.all()
        if goods.count() > 1:
            # 大于1说明有多个商品只删除一个
            for i in goods:
                if i.good_id == pid:
                    i.delete()
        # 否则删除删除整个订单
        else:
            order.delete()
        return Response({'msg': '删除成功', 'code': 200})

